#ifndef DBC_LIBRARY_H
#define DBC_LIBRARY_H

#include <string>
#include <iosfwd>
#include <set>
#include <vector>
#include <cstdint>
#include <unordered_map>

namespace DBC
{
    // 字节序
    enum class ByteOrder{
        MOTOROLA,       // 大端
        INTEL           // 小端
    };

    enum class Sign {
        UNSIGNED,
        SIGNED
    };

    enum class Multiplexor {
        NONE,
        MULTIPLEXED,
        MULTIPLEXOR
    };

    class DBCSignal
    {
        using to_list = std::set<std::string>;

        std::string                         name_;              // 信号名称
        ByteOrder                           order_;             // 信号字节序
        unsigned short                      start_bit_;         // 信号开始位
        unsigned short                      length_;            //
        Sign                                sign_;
        double                              minimum_;
        double                              maximum_;
        double                              factor_;
        double                              offset_;
        std::string                         unit_;
        Multiplexor                         multiplexor_;
        unsigned short                      multiplexor_num_;
        to_list                             to_list_;

    public:
        DBCSignal() : name_(), order_(), start_bit_(0), length_(0), sign_(Sign::UNSIGNED),
            minimum_(), maximum_(), factor_(),offset_(), multiplexor_(), multiplexor_num_() {}
        DBCSignal(DBCSignal&& sig) noexcept;

        friend std::istream& operator>>(std::istream& is, DBCSignal& sig);

        [[nodiscard]] std::string get_name() const                  { return name_; }
        [[nodiscard]] ByteOrder get_byte_order() const              { return order_; }
        [[nodiscard]] unsigned short get_startbit() const           { return start_bit_; }
        [[nodiscard]] unsigned short get_length() const             { return length_; }
        [[nodiscard]] Sign get_sign() const                         { return sign_; }
        [[nodiscard]] double get_minimum() const                    { return minimum_; }
        [[nodiscard]] double get_maximum() const                    { return maximum_; }
        [[nodiscard]] double get_factor() const                     { return factor_; }
        [[nodiscard]] double get_offset() const                     { return offset_; }
        [[nodiscard]] std::string get_unit() const                  { return unit_; }
        [[nodiscard]] Multiplexor get_multiplexor() const           { return multiplexor_; }
        [[nodiscard]] unsigned short get_multiplexed_num() const    { return multiplexor_num_; }
        [[nodiscard]] to_list get_to() const                        { return to_list_; }
    };


    class Message
    {
        using signals_t = std::vector<DBCSignal>;
        std::string name_;
        std::uint32_t id_;
        std::size_t dlc_;
        std::string from_;
        signals_t signals_;

    public:
        Message() : name_(), id_(0), dlc_(0), from_(), signals_() {}
        Message(Message&& msg) noexcept;
        Message& operator=(Message&& other) noexcept;

        using const_iterator = signals_t::const_iterator;
        friend std::istream& operator>>(std::istream& in, Message& msg);

        [[nodiscard]] std::string get_name() const                  { return name_; }
        [[nodiscard]] uint32_t get_id() const                       { return id_; }
        [[nodiscard]] std::size_t get_dlc() const                   { return dlc_; }
        [[nodiscard]] std::string get_from() const                  { return from_; }
        [[nodiscard]] auto& get_signals() const                     { return signals_; }
        [[nodiscard]] inline std::set<std::string> get_to() const;

        [[nodiscard]] const_iterator begin() const                  { return signals_.begin(); }
        [[nodiscard]] const_iterator end() const                    { return signals_.end(); }
        signals_t::const_reference operator[](std::size_t elem)     { return signals_[elem]; }
    };

    class DBCParser {
        using messages_t = std::unordered_map<uint32_t, Message>;
        using const_iterator = messages_t::const_iterator;

        messages_t message_map_{};

        void init(std::istream& stream);
    public:
        explicit DBCParser(const std::string& file_path);
        explicit DBCParser(std::istream& stream);

        const_iterator begin() const                        { return message_map_.begin(); }
        const_iterator end() const                          { return message_map_.end(); }
        // 解析CAN帧数据
        std::vector<double> parser_message(uint32_t id, const uint8_t* data, size_t data_length);
        bool create_message(uint32_t id, const std::vector<double>& phys_values, uint8_t* data, size_t data_length);

        std::uint64_t get_size()                            { return message_map_.size(); }
    };
}

#endif //DBC_LIBRARY_H